// I/O of binary tree
#ifndef BTREE_IO_HH
#define BTREE_IO_HH

#include "btree.hh"
#include <iostream>
#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>

// it is sort of ugly
#ifdef DEGREE_CORRECT
typedef btree_t<poisson_t> model_tree_t;
#else
typedef btree_t<bernoulli_t> model_tree_t;
#endif

const int empty_tree_node = -1;

////////////////////////////////////////////////////////////////
// { node data dump } &
// { ID \t L \t R \t k }
void
write_btree( model_tree_t& pbt, ofstream& ofs )
{

  int idx;
  int leaf_idx = empty_tree_node;
  int left_idx = empty_tree_node;
  int right_idx = empty_tree_node;

  ofs << pbt.get_depth() << endl;

  // write down node data
  for(int k=0; k<pbt.num_nodes(); ++k)
    {
      model_tree_t::node_ptr_t node = pbt.get_nth_node_obj(k);
      model_tree_t::node_data_t& F = node->data;
      ofs << F.write();
    }

  // write down adjacency
  for(int k=0; k<pbt.num_nodes(); ++k)
    {
      model_tree_t::node_ptr_t node = pbt.get_nth_node_obj(k);
      idx = node->hash();
      leaf_idx = node->is_leaf() ? node->leaf_idx() : empty_tree_node;
      left_idx = node->is_leaf() ? empty_tree_node : node->get_left()->hash();
      right_idx = node->is_leaf() ? empty_tree_node : node->get_right()->hash();

      ofs << idx << "\t" << left_idx << "\t" << right_idx << "\t" << leaf_idx << endl;
    }

}

// read tree dump
boost::shared_ptr< model_tree_t >
read_btree( ifstream& ifs )
{
  int depth;
  string line;
  if( getline(ifs,line,'\n') )
    {
      istringstream iss(line);
      if(!(iss>>depth))
        tree_throw("cannot read the depth");
    }
  else
    tree_throw("cannot read line");

  boost::shared_ptr< model_tree_t > ret( new model_tree_t(depth) );
  model_tree_t& Tree = *(ret.get());

  int k = 0;
  while( k<Tree.num_nodes() && getline(ifs,line,'\n') )
    {
      model_tree_t::node_ptr_t node = Tree.get_nth_node_obj(k);
      model_tree_t::node_data_t& F = node->data;
      if( ! F.read( line ) ) tree_throw("invalid line: " << line);
      F.update_param();
      ++k;
    }

  if( k != Tree.num_nodes() ) tree_throw("not enough node data");

  return ret;
}


#endif
